/*
 * Copyright (c) 2009, Jan Pastor. All Rights Reserved.
 */

package sk.jp.commons.ui;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;

import sk.jp.commons.tools.MemoryState;
import sk.jp.commons.tools.Messages;
import sk.jp.commons.utils.LogMsg;

/**
 * Memory indicator component.
 * <p>This component is primary designed for use in {@link StatusBar}.
 */
public class MemoryIndicator extends JLabel {

    public enum Msg {
        freeMem("ui.memoryindicator.free"),//Free mem
        usedMem("ui.memoryindicator.used"),//Used mem
        mb("ui.memoryindicator.mb"),//MB
        perc("ui.memoryindicator.perc"),//%
        ;
        //----------------------------------------------------------------------
        private String propKey;
        Msg(String propKey) {
            this.propKey = propKey;
        }
        public String getPropKey() {
            return propKey;
        }
        public String value() {
            return Messages.getMessage(propKey);
        }
    }

    //----------------------------------------------------------------------

    /**
     * What indicator shows.
     */
    public static enum Show {
        freeMem,
        usedMem;
    }

    /**
     * Type of presentation.
     */
    public static enum Type {
        textMb,
        textPerc,
        graph;
    }

    //----------------------------------------------------------------------

    /**
     * Timer task for periodical update of indicator value.
     */
    @SuppressWarnings({"NonStaticInnerClassInSecureContext"})
    class Refresher extends TimerTask {
        public void run() {
            update();
        }
    }

    //----------------------------------------------------------------------

    private Show show;
    private Type type;

    //----------------------------------------------------------------------

    public MemoryIndicator(int refreshPeriod, Show show, Type type,
                           MouseListener indicatorMouseListener) {
        this.show = show;
        this.type = type;

        if(indicatorMouseListener != null){
            addMouseListener(indicatorMouseListener);
        }

        //Start timer for updating
        Timer timer = new Timer(Refresher.class.getName());
        timer.schedule(new Refresher(), 250, refreshPeriod);
    }

    //----------------------------------------------------------------------

    public Show getShow() {
        return show;
    }

    public Type getType() {
        return type;
    }

    /**
     * Updates an indicator value.
     */
    private void update(){
        MemoryState ms = MemoryState.get();
        long value = getValue(ms);

        if(type == Type.textMb || type == Type.textPerc){
            setText(completeTextValue(value, ms, show, type));
        }else if(type == Type.graph){
            //TODO Dokoncit!!! call / prepare for / paint
        }
    }

    /**
     * Get indicator value in accordance with indicator properties.
     * @param ms memory state.
     * @return indicator value.
     */
    private long getValue(MemoryState ms){
        if(show == Show.freeMem){
            if(type == Type.textMb){
                return ms.convert(ms.totalFreeMemory, MemoryState.MBYTES);
            }else if(type == Type.textPerc || type == Type.graph){
                return ms.totalFreeMemoryPerc;
            }
        }else if(show == Show.usedMem){
            if(type == Type.textMb){
                return ms.convert(ms.totalUsedMemory, MemoryState.MBYTES);
            }else if(type == Type.textPerc || type == Type.graph){
                return ms.totalUsedMemoryPerc;
            }
        }

        throw new RuntimeException(LogMsg.toString("This implementation does'n support given parameters",
                                                   "show", show, "type", type));
    }

    /**
     * Makes presented text.
     * @param value current indicator value.
     * @param type type of value.
     * @return text with value to present.
     */
    protected String completeTextValue(long value, MemoryState memoryState,
                                       Show show, Type type){
        String prefix = (show == Show.freeMem) ? Msg.freeMem.value() : Msg.usedMem.value();
        String postfix = (type == Type.textMb)
                         ? " / " + memoryState.convert(memoryState.totalMaxMemory, MemoryState.MBYTES)
                           + " "+Msg.mb.value()
                         : " "+Msg.perc.value();
        return prefix+": " + value + postfix;
    }

    //todo dokoncit protected paint graph type

    //----------------------------------------------------------------------

    /**
     * Mouse on-click event handler that performs <i>garbage collect</i>.
     */
    public static class RunGcClickHandler extends MouseAdapter {
        @Override
        public void mouseClicked(MouseEvent e) {
            try {
                super.mouseClicked(e);
                onClick();
            } catch (Throwable ignored) {
            }
        }
        @SuppressWarnings({"CallToSystemGC"})
        protected void onClick(){
            System.gc();
        }
    }

}
